#!/usr/bin/perl -w

#
# Convert FreeRadius Dicrdionary files to dictionary.xml file
#

use strict;
use Data::Dumper;

my $currvendor = undef;
my $vendors = {};
my $attributes = {};

sub parseFile {
    my ($file) = @_;
    return unless $file;
    
    my $hndl = undef;

    open $hndl, $file;
    while (my $line = <$hndl>) {
	chomp $line;
	$line =~ s/(^\s+|\s+\z|#.*\z)//g;
	next if ($line =~ /^\s*\z/);
	if ($line =~ /^\$INCLUDE\s+(\S+)/) {
	    parseFile($1);
	    $currvendor = 0;
	} elsif ($line =~ /^\s*VENDOR\s+(\S+)\s+(\d+)\s*\z/) {
	    my $name = $1;
	    my $code = $2;
	    $code = hex($code) if ($code =~ /0x/);
	    
	    $currvendor = $code;
	    $vendors->{lc($name)}{name} = $name;
	    $vendors->{lc($name)}{code} = $code;
	} elsif ($line =~ /^\s*(BEGIN\-VENDOR|END-VENDOR)/) {
	    next;
	} elsif ($line =~ /^\s*ATTRIBUTE\s+(\S+)\s+([x0-9a-fA-F]+)\s+(\S+)\s*(\S+)?\s*\z/) {
	    my $name = $1;
	    my $code = $2;
	    my $type = $3;
	    my $enc = $4;
    	    $code = hex($code) if ($code =~ /0x/);
	    
	    $attributes->{lc($name)}{code} = $code;
	    $attributes->{lc($name)}{name} = $name;
	    $attributes->{lc($name)}{type} = $type;
	    $attributes->{lc($name)}{enc} = $enc ? $enc : '';
	    $attributes->{lc($name)}{vendor} = $currvendor ? $currvendor : 0;
	} elsif ($line =~ /^\s*VALUE\s+(\S+)\s+(\S+)\s+([x0-9a-fA-F]+)\s*\z/i) {
	    my $attname = $1;
	    my $valname = $2;
	    my $code = $3;
	    $code = hex($code) if ($code =~ /0x/);
	    
	    $attributes->{lc($attname)}{vals}{lc($valname)}{name} = $valname;
	    $attributes->{lc($attname)}{vals}{lc($valname)}{code} = $code;
	} else {
    	    print STDERR "$line\n";
	}
    }
    close $hndl;
}

parseFile('dictionary');


open OUT, '>dictionary.xml';
print OUT "<!-- Converted from freeradius dictionary by dict_conv.pl -->\n";
print OUT "<dictionary name=\"radius\">\n";

foreach my $vid ( sort { $vendors->{$a}{code} <=> $vendors->{$b}{code} } keys %$vendors ) {
    printf OUT "\t<vendor code=\"%d\" name=\"%s\"/>\n", $vendors->{$vid}{code}, $vendors->{$vid}{name};
}

print OUT "\n";

foreach my $id ( sort { 
		    $attributes->{$a}{vendor} == $attributes->{$b}{vendor} ? 
			$attributes->{$a}{code} <=> $attributes->{$b}{code} : 
			$attributes->{$a}{vendor} <=> $attributes->{$b}{vendor}
		} keys %$attributes ) {
    my $attr = $attributes->{$id};

    # Skip NON-Protocol attributes with code > 255
    next if ($attr->{code} > 255);
	    
    printf OUT "\t<attribute vendor=\"%d\" code=\"%d\" name=\"%s\" type=\"%s\" encoding=\"%s\"", $attr->{vendor}, $attr->{code}, $attr->{name}, $attr->{type}, $attr->{enc};

    unless (exists $attr->{vals}) {
	print OUT "/>\n";
    } else {
	print OUT ">\n";
	
	foreach my $kid ( sort { $attr->{vals}{$a}{code} <=> $attr->{vals}{$b}{code} } keys %{$attr->{vals}} ) {
	    printf OUT "\t\t<value code=\"%d\" name=\"%s\"/>\n", $attr->{vals}{$kid}{code}, $attr->{vals}{$kid}{name};
	}
	
	print OUT "\t</attribute>\n";
    }
}

print OUT "</dictionary>\n";
